﻿using System;
using System.Collections.Generic;
using System.Text;
using Pixysoft.Framework.Verifications;
using Pixysoft.Framework.Logs;
using Pixysoft.Collections;
using System.Threading;
using System.Web;

namespace Pixysoft.Framework.Comet.Core
{
    /// <summary>
    /// sendercode 大写 不能使用readwritelocker，导致了死锁。
    /// </summary>
    class CometRequestPool : ICometRequestPool
    {
        private volatile Dictionary<string, ICometRequest> pools = new Dictionary<string, ICometRequest>();


        private static volatile CometRequestPool instance;

        private static object syncRoot = new Object();

        public static CometRequestPool Instance
        {
            get
            {
                if (instance == null)
                {
                    lock (syncRoot)
                    {
                        if (instance == null)
                        {
                            instance = new CometRequestPool();
                        }
                    }
                }
                return instance;
            }
        }


        /// <summary>
        /// 建立一个本地普通的comet链接
        /// 链接到持久池 如果请求存在，则替换 否则新建
        /// </summary>
        /// <param name="senderCode"></param>
        /// <param name="result"></param>
        public ICometRequest Connect(string senderCode, HttpContext context)
        {
            LoggerHelper.Debug("begin connect comet request, sendercode = {0}", senderCode);

            ICometRequest request = null;

            ICometRequest oldrequest = null;

            if (ContainsRequest(senderCode))
            {
                request = GetRequest(senderCode);

                if (!(request is CometRequest))
                {
                    LoggerHelper.Debug("{0}::existed comet request is not typeof comet request, remove it.", senderCode);

                    oldrequest = request;

                    RemoveRequest(request);

                    request = null;
                }
            }

            if (request == null)
            {
                LoggerHelper.Debug("{0}::comet request do not existed, create new one", senderCode);

                request = new CometRequest(senderCode);

                if (oldrequest != null)
                {
                    request.TransferFrom(oldrequest);

                    oldrequest = null;

                    LoggerHelper.Debug("{0}::transfer old request to new request.", senderCode);
                }

                this.AddRequest(senderCode, request);
            }
            else
            {
                LoggerHelper.Debug("{0}:old request existed, just subscribe. msg.count:{1}", request.RequestUid, request.MessageCount);
            }

            request.Subscribe(context);

            return request;
        }

        /// <summary>
        /// 对输入的comet请求封装成为广播模式，然后客户再调用
        /// 组播模式
        /// </summary>
        /// <param name="request"></param>
        /// <param name="senderCode"></param>
        /// <returns></returns>
        public ICometRequest BroadcastConnect(ICometRequest bcrequest, string senderCode, HttpContext context)
        {
            LoggerHelper.Debug("{0}::begin broadcast connect comet request", senderCode);

            ICometRequest request = null;

            ICometRequest oldrequest = null;

            //2010-05-27 这里首先要清除旧的broadcast 否则指针一直指向旧的数据

            //2010-05-31 在persist模式下，旧的broadcast仍然要获取，因为旧的数据需要导入新的request里面。

            LoggerHelper.Debug("{0}::remove old broadcast request.", senderCode);

            oldrequest = RemoveRequest(senderCode);

            if (request == null)
            {
                LoggerHelper.Debug("{0}::comet broadcast request do not existed, create new one", senderCode);

                request = new CometBroadcastRequest(bcrequest, senderCode);

                if (oldrequest != null)
                {
                    request.TransferFrom(oldrequest);

                    oldrequest = null;
                }

                this.AddRequest(senderCode, request);
            }

            request.Subscribe(context);

            return request;
        }



        /// <summary>
        /// 注销链接 但是不影响请求本身
        /// </summary>
        /// <param name="senderCode"></param>
        public ICometRequest DisConnect(string senderCode)
        {
            if (!ContainsRequest(senderCode))
            {
                LoggerHelper.Debug("{0}:: disconnect request, pool do not contain it, return null.", senderCode);

                return null;
            }

            ICometRequest request = GetRequest(senderCode);

            return DisConnect(request);
        }

        /// <summary>
        /// 注销链接 但是不影响请求本身
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public ICometRequest DisConnect(ICometRequest request)
        {
            LoggerHelper.Debug("{0}::dis connect request.", request.SenderCode);

            request.UnSubscribe();

            return request;
        }



        /// <summary>
        /// 删除请求 同时删除对应的链接 状态= disposed
        /// </summary>
        /// <param name="senderCode"></param>
        /// <returns></returns>
        public ICometRequest RemoveRequest(string senderCode)
        {
            LoggerHelper.Debug("{0}::try to remove request @ comet  request pool.", senderCode);

            if (!ContainsRequest(senderCode))
            {
                LoggerHelper.Debug("{0}::remove request. request do not existed.", senderCode);

                return null;
            }

            try
            {
                ICometRequest request = pools[senderCode];

                lock (syncRoot)
                {
                    pools.Remove(senderCode);
                }

                request.UnSubscribe();

                //09-11-14 在多线程中，有可能当前req被其他线程取消了 因此要设置标志位通知

                request.Dispose();

                LoggerHelper.Debug("{0}:: request removed from pool.", senderCode);

                return request;
            }
            catch (Exception ex)
            {
                if (!Exceptions.IsHandled(ex))
                    LoggerHelper.Fatal(ex);

                return null;
            }
        }

        /// <summary>
        /// 删除请求 同时删除对应的链接 状态= disposed
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public ICometRequest RemoveRequest(ICometRequest request)
        {
            return RemoveRequest(request.SenderCode);
        }

        /// <summary>
        /// 是否包含请求
        /// </summary>
        /// <param name="senderCode"></param>
        /// <returns></returns>
        public bool ContainsRequest(string senderCode)
        {
            try
            {
                LoggerHelper.Debug("{0}:: check pool contains request. count:{1}", senderCode, pools.Count);

                return pools.ContainsKey(senderCode);
            }
            catch (Exception ex)
            {
                LoggerHelper.Fatal(ex);

                return false;
            }
        }

        /// <summary>
        /// 添加请求
        /// </summary>
        /// <param name="senderCode"></param>
        /// <param name="request"></param>
        private void AddRequest(string senderCode, ICometRequest request)
        {
            LoggerHelper.Debug("{0}::add request at comet request pool.", senderCode);

            RemoveRequest(senderCode);

            try
            {
                pools.Add(senderCode, request);
            }
            catch (Exception ex)
            {
                LoggerHelper.Fatal(ex);
            }
        }


        public ICometRequest GetRequest(string senderCode)
        {
            if (!ContainsRequest(senderCode))
                return null;

            try
            {
                return pools[senderCode];
            }
            catch (Exception ex)
            {
                LoggerHelper.Fatal(ex);

                return null;
            }
        }

        /// <summary>
        /// 检查是否内存丢失
        /// </summary>
        /// <param name="senderCode"></param>
        /// <param name="request"></param>
        public void Visit(string senderCode, ICometRequest request)
        {
            if (!ContainsRequest(senderCode))
                pools.Add(senderCode, request);
        }


        public int Count
        {
            get
            {
                return pools.Count;
            }
        }
    }
}
